<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <meta http-equiv="Content-Language" content="en" />
    <title>s6: the s6-sudod program</title>
    <meta name="Description" content="s6: the s6-sudod program" />
    <meta name="Keywords" content="s6 s6-sudod sudo setuid suid unix privilege gain getpeereid server" />
    <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> -->
  </head>
<body>

<p>
<a href="index.html">s6</a><br />
<a href="//skarnet.org/software/">Software</a><br />
<a href="//skarnet.org/">skarnet.org</a>
</p>

<h1> The <tt>s6-sudod</tt> program </h1>

<p>
<tt>s6-sudod</tt> receives command-line arguments, environment variables
and standard descriptors from a peer <a href="s6-sudoc.html">s6-sudoc</a>
program over a Unix socket, then forks another program.
</p>

<h2> Interface </h2>

<pre>
     s6-sudod [ -0 ] [ -1 ] [ -2 ] [ -d ] [ -t <em>timeout</em> ] [ <em>sargv...</em> ]
</pre>

<ul>
 <li> s6-sudod gets 3 file descriptors via fd-passing over a Unix socket that
must be open on its descriptors 0 and 1. (The received descriptors will be the
stdin, stdout and stderr of the server program.) It expects a
<a href="s6-sudoc.html">s6-sudoc</a> process to be sending them on the
client side. </li>
 <li> It also receives a list of command-line arguments <em>cargv...</em>, and
an environment <em>clientenv</em>. </li>
 <li> s6-sudod forks and executes <em>sargv...</em> <em>cargv</em>...
The client command line is appended to the server command line. </li>
 <li> s6-sudod waits for its child to exit and transmits its exit code
to the peer <a href="s6-sudoc.html">s6-sudoc</a> process. It then exits 0. </li>
</ul>

<h2> Environment </h2>

<p>
s6-sudod transmits its own environment to its child, plus the environment sent
by <a href="s6-sudoc.html">s6-sudoc</a>, filtered in the following manner:
for every variable sent by <a href="s6-sudoc.html">s6-sudoc</a>, if the
variable is <strong>present but empty</strong> in s6-sudod's environment, then
its value is overriden by the value given by s6-sudoc. A variable that is
already nonempty, or that doesn't exist, in s6-sudod's environment, will not
be transmitted to the child. In other words:
</p>

<ul>
 <li> If there's no variable <tt>X</tt> in s6-sudod's environment, the child
will have no variable <tt>X</tt> defined </li>
 <li> If there's a non-empty variable <tt>X</tt> in s6-sudod's environment,
the child will inherit that variable, with its value, from s6-sudod </li>
 <li> If there's an empty variable <tt>X</tt> in s6-sudod's environment,
and s6-sudoc transmits variable <tt>X</tt>, then the child will inherit that
variable with the value from s6-sudoc. (If s6-sudoc does not transmit <tt>X</tt>,
the variable will be present, but empty, in the child's environment.) </li>
</ul>

<h2> Options </h2>

<ul>
 <li> <tt>-0</tt>&nbsp;: do not inherit stdin from s6-sudoc. The child will be
run with its stdin pointing to <tt>/dev/null</tt> instead. </li>
 <li> <tt>-1</tt>&nbsp;: do not inherit stdout from s6-sudoc. The child will be
run with its stdout pointing to <tt>/dev/null</tt> instead. </li>
 <li> <tt>-2</tt>&nbsp;: do not inherit stderr from s6-sudoc. The child will be
run with its stderr being a copy of s6-sudod's stderr instead. (This is useful
to still log the child's error messages without sending them to the client.) </li>
 <li> <tt>-d</tt>&nbsp;: detach. The child will keep running until it naturally
exits, even if the client disconnects. Setting this option also enforces
<tt>-0</tt>, <tt>-1</tt> and <tt>-2</tt>. Bear in mind that this option
relinquishes a lot of control over the child, and administrators should make sure
it is appropriately short-lived. </li>
 <li> <tt>-t&nbsp;<em>timeout</em></tt>&nbsp;: if s6-sudod has not
received all the needed data from the client after <em>timeout</em>
milliseconds, it will exit without spawning a child. By default, <em>timeout</em>
is 0, meaning infinite. This mechanism exists to protect the server from
malicious or buggy clients that would uselessly consume resources. </li>
</ul>

<h2> Usage example </h2>

<p>
 The typical use of s6-sudod is in a
<a href="localservice.html">local service</a> with a
<a href="s6-ipcserver.html">s6-ipcserver</a> process listening on a Unix
socket, an <a href="s6-ipcserver-access.html">s6-ipcserver-access</a> process
performing client authentication and access control, and possibly a
<a href="s6-envdir.html">s6-envdir</a>
process setting up the environment variables that will be accepted by
s6-sudod. The following script, meant to be a <em>run script</em> in a
<a href="servicedir.html">service directory</a>,
will set up a privileged program:
</p>

<pre>
#!/command/execlineb -P
fdmove -c 2 1
fdmove 1 3
s6-envuidgid serveruser
s6-ipcserver -U -1 -- serversocket
s6-ipcserver-access -v2 -l0 -i rules --
exec -c
s6-envdir env
s6-sudod
sargv
</pre>

<ul>
 <li> <a href="//skarnet.org/software/execline/execlineb.html">execlineb</a>
executes the script. </li>
 <li> <a href="//skarnet.org/software/execline/fdmove.html">fdmove</a> makes
sure the script's error messages are sent to the service's logger. </li>
 <li> <a href="//skarnet.org/software/execline/fdmove.html">fdmove</a>
redirects the script's stdout to file descriptor 3. This is useful if
the service directory contains a <tt>notification-fd</tt> file containing
<tt>3</tt>, so the daemon can perform
<a href="notifywhenup.html">readiness notification</a> by writing a
newline to its stdout. (The
<tt>-1</tt> option to s6-ipcserver tells it to do this.) </li>
 <li> <a href="s6-envuidgid.html">s6-envuidgid</a>
sets the UID, GID and GIDLIST environment variables for s6-ipcserver to interpret. </li>
 <li> <a href="s6-ipcserver.html">s6-ipcserver</a> binds to <em>serversocket</em>,
drops its privileges to those of <em>serveruser</em>, and announces its
readiness. Then, for every client connecting to <em>serversocket</em>:
  <ul>
   <li> <a href="s6-ipcserver-access.html">s6-ipcserver-access</a> checks the
client's credentials according to the rules in directory <em>rules</em>.
   <li> <a href="//skarnet.org/software/execline/exec.html">exec -c</a>
clears the environment. </li>
   <li> <a href="//skarnet.org/software/s6/s6-envdir.html">s6-envdir</a>
sets environment variables according to the directory <em>env</em>. You can
make sure that a variable VAR will be present but empty by performing
<tt>echo > env/VAR</tt>. (A single newline is interpreted by s6-envdir as
an empty variable; whereas if <tt>env/VAR</tt> is totally empty, then the
VAR variable will be removed from the environment.) </li>
   <li> s6-sudod reads a command line <em>cargv</em>, a client environment
and file descriptors over the socket. </li>
   <li> s6-sudod spawns <tt>sargv cargv</tt>. </li>
  </ul>
 (Actually, <a href="s6-ipcserver.html">s6-ipcserver</a> does not do this
itself: it executes into other programs that each do one of the tasks. But for
our example, it does not matter.) </li>
</ul>

<p>
 This means that user <em>clientuser</em> running
<tt><a href="s6-sudo.html">s6-sudo</a> serversocket cargv</tt> will be
able, if authorized by the configuration in <em>rules</em>, to run
<tt>sargv cargv</tt> as user <em>serveruser</em>, with stdin,
stdout, stderr and the environment variables properly listed in <em>env</em>
transmitted to <em>sargv</em>.
</p>

<h2> Notes </h2>

<ul>
 <li> If the <tt>-d</tt> option to s6-sudod has not been given, and
s6-sudoc is killed (or exits after <em>timeoutrun</em> milliseconds)
while the server program is still running, s6-sudod will send a SIGTERM and a
SIGCONT to its child, then exit 1. However, sending a SIGTERM to the child
does not guarantee that it will die; and
if it keeps running, it might still read from the file that
was s6-sudoc's stdin, or write to the files that were s6-sudoc's stdout or
stderr. <strong>This is a potential security risk</strong>.
Administrators should audit their server programs to make sure this does not
happen. </li>
 <li> More generally, anything using signals or terminals will not be
handled transparently by the s6-sudoc + s6-sudod mechanism. The mechanism
was designed to allow programs to gain privileges in specific situations:
short-lived, simple, noninteractive processes. It was not designed to emulate
the full suid functionality and will not go out of its way to do so. </li>
 <li> Administrators should also make sure that it's not a problem if
s6-sudod's child keeps running after the s6-sudoc client exits, if they
have given the <tt>-d</tt> option to s6-sudod. In particular, they should
study what happens if another connection to the same service occurs while
an instance is still running. </li>
 <li> <em>sargv</em> may be empty. In that case, the client is in complete
control of the command line executed as <em>serveruser</em>. This setup is
permitted by s6-sudod, but it is very dangerous, and extreme attention should
be paid to the construction of the s6-ipcserver-access rules. </li>
</ul>

</body>
</html>
